home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-01-25 | 20.0 KB | 651 lines | [TEXT/CWIE] |
- //========================================================================================
- //
- // Burn Time Code.c - Burn Time Code on to a frame in Adobe Premiere¬.
- //
- // Written by Bryan K. "Beaker" Ressler.
- //
- // Copyright ⌐ 1993-96, Adobe Systems Incorporated, all rights reserved worldwide.
- //
- // Version 1.00 10/20/93 Original version.
- // Version 1.01 9/12/94 Updated for 4.0.
- // Version 1.02 10/6/95 Updated for 4.2 and CW7.
- //
- //========================================================================================
-
- //========================================================================================
- // Includes - use precompiled headers if compiling with CodeWarrior.
- //========================================================================================
- #ifdef __MWERKS__
- #ifdef powerc
- #include "PremierePPC"
- #else
- #include "Premiere68k"
- #endif
- #else
- #include "Premiere.h"
- #endif
-
- //========================================================================================
- // Resource IDs
- //========================================================================================
- #define kDialog 100 // DLOG - Our setings dialog
- #define kStrings 100 // STR# - Our string list
-
- //========================================================================================
- // Strings in our string list
- //========================================================================================
- #define kBkgdPrompt 1 // Color picker prompt for background color
- #define kTextPrompt 2 // Color picker prompt for text color
-
- //========================================================================================
- // Settings dialog items
- //========================================================================================
- enum {
- riOK = 1,
- riCancel,
- riSample,
- riStartTimeText,
- riStartTimeInterp, // 5
- riDropFrameCheck,
- riPositionPopup,
- riBkgdSwatch,
- riFontPopup,
- riBoldCheck, // 10
- riItalicCheck,
- riTextSwatch
- };
-
- enum { // Time code positions
- posLeft = 1,
- posCenter,
- posRight
- };
-
- //========================================================================================
- // Private types
- //========================================================================================
- typedef struct {
- short version; // BCD record version number (e.g. 0x0120 = 1.2)
- long startTime; // Start time in frames
- Str255 fontName; // The font for the time code display
- RGBColor bkgdColor; // The background color
- RGBColor textColor; // The text color
- short position; // Time code position (left/center/right)
- Boolean isBold; // Bold text?
- Boolean isItalic; // Italic text?
- Boolean dropFrame; // Drop-frame time code?
- } BTCSpecRec, *BTCSpecPtr, **BTCSpecHdl;
-
- typedef struct {
- BTCSpecRec btcSpec;
- VideoHandle theData;
- } LocalRec, **LocalHand;
-
- //========================================================================================
- // Constants
- //========================================================================================
- #define kSpecsVersion 0x0120 // Version of our specs record (1.2)
-
- //========================================================================================
- // Static prototypes
- //========================================================================================
- static void InitBTCSpec(BTCSpecPtr bs);
- static short BTCSetup(VideoHandle theData);
- static void SwapBTCColors(DialogPtr dialog, BTCSpecPtr bs);
- static Boolean OptionDown(void);
- static pascal Boolean BTCFilter(DialogPtr dialog, EventRecord *event, short *hit);
- static short FindMenuItem(MenuHandle menu, StringPtr name);
- static short SetupFontMenu(BTCSpecPtr bs, MenuHandle menu);
- static pascal void SwatchItem(DialogPtr dialog, short item);
- static pascal void SampleItem(DialogPtr dialog, short item);
- static void ImageProc(BTCSpecPtr bs, GWorldPtr src, GWorldPtr target, Rect *overlaySize,
- short fps, long part, short sizeFlags);
- static PicHandle MakeOverlayPicture(BTCSpecPtr bs, short width, short height, short fps,
- long part, short sizeFlags);
- static short SetupText(BTCSpecPtr bs, Rect *box);
- static void DrawTimeCode(BTCSpecPtr bs, Rect *box, short textSize, short fps, long part);
-
- //========================================================================================
- // Dispatcher for filter functions.
- //========================================================================================
- pascal short main (short selector, VideoHandle theData)
- {
- BTCSpecHdl camHdl;
- CGrafPtr oldWorld;
- GDHandle oldDevice;
- short fps, result = 0;
-
- switch (selector) {
- case fsExecute:
- camHdl = (BTCSpecHdl)(*theData)->specsHandle;
- if (camHdl != nil) {
- GetGWorld(&oldWorld, &oldDevice);
- SetGWorld((*theData)->destination, nil);
- HLock((Handle)camHdl);
- fps = (*theData)->fps;
- if ((*camHdl)->dropFrame)
- fps |= 0x8000;
- ImageProc(*camHdl, (*theData)->source, (*theData)->destination, nil, fps,
- (*theData)->part, (*theData)->sizeFlags);
- HUnlock((Handle)camHdl);
- ForeColor(blackColor);
- BackColor(whiteColor);
- SetGWorld(oldWorld, oldDevice);
- } else result = 1;
- break;
-
- case fsSetup:
- result = BTCSetup(theData);
- break;
- }
- return(result);
- }
-
- //========================================================================================
- // Initialize a burn time code specification record with reasonable default values. If bs
- // is in a Handle, it should be locked before calling this routine, because we call
- // GetFontName, which moves memory.
- //========================================================================================
- static void InitBTCSpec(BTCSpecPtr bs)
- {
- RGBColor white = { 0xffff, 0xffff, 0xffff };
- RGBColor black = { 0x0000, 0x0000, 0x0000 };
-
- bs->version = kSpecsVersion;
- bs->startTime = 0;
- GetFontName(applFont, bs->fontName);
- bs->bkgdColor = black;
- bs->textColor = white;
- bs->position = posCenter;
- bs->isBold = false;
- bs->isItalic = false;
- bs->dropFrame = false;
- }
-
- //========================================================================================
- // Conduct the Burn Time Code filter's setup dialog.
- //========================================================================================
- static short BTCSetup(VideoHandle theData)
- {
- Str63 prompt, timeStr;
- RGBColor oldColor, newColor;
- LocalHand ldata;
- MenuHandle menu;
- DialogPtr dialog;
- GrafPtr oldPort;
- BTCSpecPtr bs;
- long temp;
- short item, result = 0;
- short origfps, fps;
- unsigned char blank = 0;
- Boolean redrawSample = false;
-
- InitCursor();
- GetPort(&oldPort);
- ldata = (LocalHand)NewHandleClear(sizeof(LocalRec));
- if (ldata == nil)
- return(1);
-
- // Get our spec if one was provided, otherwise initialize with defaults
- HLock((Handle)ldata);
- (*ldata)->theData = theData;
- bs = &(*ldata)->btcSpec;
- origfps = fps = (*theData)->fps;
- if (bs->dropFrame)
- fps |= 0x8000;
- if ((*theData)->specsHandle) {
- BlockMove(*(*theData)->specsHandle, (Ptr)bs, sizeof(BTCSpecRec));
- if (bs->version != kSpecsVersion)
- InitBTCSpec(bs);
- } else InitBTCSpec(bs);
-
- // Get the dialog
- dialog = GetNewDialog(kDialog, nil, (WindowPtr)-1);
- SetPort(dialog);
- CenterWindow(dialog, &(*GetMainDevice())->gdRect);
- SetWRefCon(dialog,(long)ldata);
-
- // Set up the user items
- UserItem(dialog, riSample, SampleItem);
- UserItem(dialog, riBkgdSwatch, SwatchItem);
- UserItem(dialog, riTextSwatch, SwatchItem);
-
- // Set control values
- SetCValue(dialog, riBoldCheck, bs->isBold);
- SetCValue(dialog, riItalicCheck, bs->isItalic);
- SetCValue(dialog, riPositionPopup, bs->position);
- SetCValue(dialog, riDropFrameCheck, bs->dropFrame);
-
- // Set edit item text
- Time2Str(bs->startTime, timeStr, fps, tsHours);
- SetEText(dialog, riStartTimeText, timeStr);
- ParamText(timeStr, &blank, &blank, &blank);
- SelIText(dialog, riStartTimeText, 0, 32767);
-
- // Set up the font menu
- menu = (MenuHandle)GetCRef(dialog, riFontPopup);
- item = SetupFontMenu(bs, menu);
- SetCValue(dialog, riFontPopup, item);
- WidenMenu(dialog, riFontPopup);
-
- // Pose the dialog
- ShowModal(dialog);
- do {
- item = 0;
- if (redrawSample) {
- redrawSample = false;
- SampleItem(dialog, riSample);
- }
- PrModalDialog(BTCFilter, &item);
- switch (item) {
- case riOK:
- // Store our camcorder filter specification
- if ((*theData)->specsHandle) {
- SafeSetHandleSize((*theData)->specsHandle, sizeof(BTCSpecRec));
- BlockMove((Ptr)bs, *(*theData)->specsHandle,
- sizeof(BTCSpecRec));
- } else {
- (*theData)->specsHandle = NewHandle(sizeof(BTCSpecRec));
- if ((*theData)->specsHandle)
- BlockMove((Ptr)bs, *(*theData)->specsHandle,
- sizeof(BTCSpecRec));
- }
- break;
- case riCancel:
- item = riOK;
- result = 1;
- break;
- case riStartTimeText:
- GetEText(dialog, item, timeStr);
- fps = origfps;
- if (bs->dropFrame)
- fps |= 0x8000;
- bs->startTime = Str2Time(timeStr + 1, *timeStr, fps);
- Time2Str(bs->startTime, timeStr, fps, tsHours);
- ParamText(timeStr, &blank, &blank, &blank);
- InvalItem(dialog, riStartTimeInterp);
- redrawSample = true;
- break;
- case riDropFrameCheck:
- bs->dropFrame = !bs->dropFrame;
- SetCValue(dialog, item, bs->dropFrame);
- redrawSample = true;
- break;
- case riPositionPopup:
- bs->position = GetCValue(dialog, item);
- redrawSample = true;
- break;
- case riBkgdSwatch:
- if (OptionDown())
- SwapBTCColors(dialog, bs);
- else {
- GetIndString(prompt, kStrings, kBkgdPrompt);
- oldColor = bs->bkgdColor;
- if (GeneralGetColor(prompt, &oldColor, &newColor)) {
- bs->bkgdColor = newColor;
- SwatchItem(dialog, item);
- }
- SetPort(dialog);
- ParamText(timeStr, &blank, &blank, &blank);
- }
- redrawSample = true;
- break;
- case riFontPopup:
- temp = GetCValue(dialog, item);
- menu = (MenuHandle)GetCRef(dialog, riFontPopup);
- GetItem(menu, temp, bs->fontName);
- redrawSample = true;
- break;
- case riBoldCheck:
- bs->isBold = !bs->isBold;
- SetCValue(dialog, item, bs->isBold);
- redrawSample = true;
- break;
- case riItalicCheck:
- bs->isItalic = !bs->isItalic;
- SetCValue(dialog, item, bs->isItalic);
- redrawSample = true;
- break;
- case riTextSwatch:
- if (OptionDown())
- SwapBTCColors(dialog, bs);
- else {
- GetIndString(prompt, kStrings, kTextPrompt);
- oldColor = bs->textColor;
- if (GeneralGetColor(prompt, &oldColor, &newColor)) {
- bs->textColor = newColor;
- SwatchItem(dialog, item);
- }
- SetPort(dialog);
- ParamText(timeStr, &blank, &blank, &blank);
- }
- redrawSample = true;
- break;
- default:
- break;
- }
- } while (item != riOK);
-
- // Clean up
- HUnlock((Handle)ldata);
- DisposeModal(dialog);
- DisposeHandle((Handle)ldata);
- SetPort(oldPort);
- return(result);
- }
-
- //========================================================================================
- // Swaps the background and text colors
- //========================================================================================
- static void SwapBTCColors(DialogPtr dialog, BTCSpecPtr bs)
- {
- RGBColor temp;
-
- temp = bs->bkgdColor;
- bs->bkgdColor = bs->textColor;
- bs->textColor = temp;
- SwatchItem(dialog, riBkgdSwatch);
- SwatchItem(dialog, riTextSwatch);
- }
-
- //========================================================================================
- // Returns true if the Option key is currently down.
- //========================================================================================
- static Boolean OptionDown(void)
- {
- return((GetModifiers(nil) & bOption) != 0);
- }
-
- //========================================================================================
- // Dialog filter for the Burn Time Code setup dialog. It does the hits on popup control
- // items.
- //========================================================================================
- static pascal Boolean BTCFilter(DialogPtr dialog, EventRecord *event, short *hit)
- {
- Point where;
- ControlHandle thecontrol;
- short which, oldval, part;
- Boolean result = false;
-
- result = modalfilter(dialog, event, hit);
- if (!result && event->what == mouseDown) {
- where = event->where;
- GlobalToLocal(&where);
- if (which = FindDItem(dialog, where) + 1) {
- if (FindControl(where, dialog, &thecontrol)) {
- oldval = GetCtlValue(thecontrol);
- part = TrackControl(thecontrol, where, nil);
- if (oldval != GetCtlValue(thecontrol)) {
- *hit = which;
- result = true;
- } else if (part) {
- *hit = which;
- result = true;
- } else {
- *hit = 0;
- result = true;
- }
- }
- }
- }
-
- return(result);
- }
-
- //========================================================================================
- // Given a menu and an item name, return the item number or 0 if not found.
- //========================================================================================
- static short FindMenuItem(MenuHandle menu, StringPtr name)
- {
- short numItems, item = 0, i = 0;
- Str255 str;
-
- numItems = CountMItems(menu);
- for (i = 1; i <= numItems; i++) {
- GetItem(menu, i, str);
- if (StringsSame(str, name))
- item = i;
- }
- return item;
- }
-
- //========================================================================================
- // Deletes any existing item from the font menu, appends all installed font names, then
- // tries to find the current font in the menu, returning its item number if found or 0 if
- // not found.
- //========================================================================================
- static short SetupFontMenu(BTCSpecPtr bs, MenuHandle menu)
- {
- short i;
-
- // First, delete all existing items from the menu
- i = CountMItems(menu);
- do DelMenuItem(menu, i--); while (i > 0);
-
- // Add the fonts
- AddResMenu(menu, 'FONT');
-
- // Look for the current font in the menu
- i = FindMenuItem(menu, bs->fontName);
- return(i);
- }
-
- //========================================================================================
- // Draw the color swatches (both handled by this user item proc).
- //========================================================================================
- static pascal void SwatchItem(DialogPtr dialog, short item)
- {
- Rect box;
- RGBColor color;
- LocalHand ldata;
-
- ldata = (LocalHand)GetWRefCon(dialog);
- switch (item) {
- case riBkgdSwatch:
- color = (*ldata)->btcSpec.bkgdColor;
- break;
- case riTextSwatch:
- color = (*ldata)->btcSpec.textColor;
- break;
- }
- GetDRect(dialog, item, &box);
- FrameRect(&box);
- InsetRect(&box, 1, 1);
- DitherBox(dialog, &box, &color);
- SetGray(0);
- }
-
- //========================================================================================
- // Draw the sample in the setup dialog.
- //========================================================================================
- static pascal void SampleItem(DialogPtr dialog, short item)
- {
- Rect all, box;
- LocalHand ldata;
- VideoHandle theData;
- GWorldPtr src, dest;
- Rect overlaySize = { 0, 0, 480, 640 }; // Render at 640 x 480 for preview
- short fps;
-
- ldata = (LocalHand)GetWRefCon(dialog);
- theData = (*ldata)->theData;
-
- src = (*theData)->source;
- dest = (*theData)->destination;
- box = src->portRect;
-
- GetDRect(dialog, item, &all);
- FrameRect(&all);
- InsetRect(&all, 1, 1);
-
- // ldata is already locked here (by the dialog routine)
- fps = (*theData)->fps;
- if ((*ldata)->btcSpec.dropFrame)
- fps |= 0x8000;
- ImageProc(&(*ldata)->btcSpec, src, dest, &overlaySize, fps , 0, (*theData)->sizeFlags);
- CopyBits((BitMap *)&dest->portPixMap, &dialog->portBits, &box, &all, ditherCopy,
- dialog->visRgn);
- }
-
- //========================================================================================
- // Apply our filter between the src and dest worlds. The overlaySize rectangle allows the
- // caller to force the picture to be rendered at a given size. This allows the SampleItem
- // proc to image the overlay picture at the output options size, so the scaled down over-
- // lay will be more accurate. Note that the image is still overlayed at the size
- // specified. FPS SHOULD ALREADY HAVE THE HIGH BIT SET IF DROP FRAME IS TURNED ON!
- //========================================================================================
- static void ImageProc(BTCSpecPtr bs, GWorldPtr src, GWorldPtr target, Rect *overlaySize,
- short fps, long part, short sizeFlags)
- {
- Rect box;
- GDHandle oldGD;
- PicHandle overlay;
- GWorldPtr oldGW;
- short hSize, vSize;
-
- // Point at target
- GetGWorld(&oldGW, &oldGD);
- SetGWorld(target, nil);
-
- // Copy the frame into the target
- box = src->portRect;
- CopyBits((BitMap*)&src->portPixMap, (BitMap*)&target->portPixMap, &box, &box,
- srcCopy, nil);
-
- // Create the camcorder overlay picture and draw it over the destination port.
- if (overlaySize != nil) {
- hSize = overlaySize->right - overlaySize->left;
- vSize = overlaySize->bottom - overlaySize->top;
- } else {
- hSize = box.right - box.left;
- vSize = box.bottom - box.top;
- }
- overlay = MakeOverlayPicture(bs, hSize, vSize, fps, part, sizeFlags);
- if (overlay)
- DrawPicture(overlay, &box);
- KillPicture(overlay);
-
- // Restore
- ForeColor(blackColor); PenNormal();
- SetGWorld(oldGW, oldGD);
- }
-
- //========================================================================================
- // The supervisor routine that constructs the timecode overlay picture. Returns nil if
- // there wasn't enough memory to build the picture.
- //========================================================================================
- static PicHandle MakeOverlayPicture(BTCSpecPtr bs, short width, short height, short fps,
- long part, short sizeFlags)
- {
- Rect box;
- short textSize;
- PicHandle pict;
-
- // Build the picture bounds and compensate for fields, half-vertical, and half-horiz-
- // ontal flags.
- SetRect(&box, 0, 0, width, height);
- if (sizeFlags & gvHalfH)
- box.right *= 2;
- if (sizeFlags & (gvHalfV + gvFieldsEven + gvFieldsOdd))
- box.bottom *= 2;
- if (sizeFlags & (gvFieldsEven + gvFieldsOdd))
- part /= 2;
-
- // Build the overlay picture
- pict = OpenPicture(&box);
-
- // Start clean
- ForeColor(blackColor);
- PenNormal();
-
- // Set up text parameters
- textSize = SetupText(bs, &box);
-
- // Burn the timecode
- DrawTimeCode(bs, &box, textSize, fps, part);
-
- // End clean
- ForeColor(blackColor);
- PenNormal();
-
- ClosePicture();
- return(pict);
- }
-
- //========================================================================================
- // Set up the current port with the appropriate font, size, style, and mode.
- //========================================================================================
- static short SetupText(BTCSpecPtr bs, Rect *box)
- {
- short fNum, size;
- Style style;
-
- // Get the information
- GetFNum(bs->fontName, &fNum);
- size = (box->right - box->left) / 20;
- if (size < 12) size = 12;
- style = normal;
- if (bs->isBold)
- style |= bold;
- if (bs->isItalic)
- style |= italic;
-
- // Apply it
- TextFont(fNum);
- TextFace(style);
- TextMode(srcOr);
- TextSize(size);
-
- return(size);
- }
-
- //========================================================================================
- // Draw the "burned-in" timecode.
- //========================================================================================
- static void DrawTimeCode(BTCSpecPtr bs, Rect *box, short textSize, short fps, long part)
- {
- Str63 timeStr;
- FontInfo info;
- Rect tcBox;
- RGBColor fiftyPercentGray = { 0x7fff, 0x7fff, 0x7fff };
- short width, height, tcWidth, tcGutter;
-
- // Build the timecode string and get its width
- Time2Str(bs->startTime + part, timeStr, fps, tsHours);
- tcWidth = StringWidth(timeStr);
- tcGutter = tcWidth * 4 / 100; // 4% gutters on each side
-
- // Build the box in which the timecode string will be drawn
- tcBox = *box;
- width = tcBox.right - tcBox.left;
- height = tcBox.bottom - tcBox.top;
- InsetRect(&tcBox, width * 12 / 100, height * 12 / 100); // 12% - title-safe
- tcBox.top = tcBox.bottom - (textSize * 120 / 100); // 120% of the point size
- switch (bs->position) {
- case posLeft:
- tcBox.right = tcBox.left + tcGutter + tcWidth + tcGutter;
- break;
- case posCenter:
- tcWidth = tcWidth + tcGutter * 2;
- tcBox.left += ((tcBox.right - tcBox.left) - tcWidth) / 2;
- tcBox.right = tcBox.left + tcWidth;
- break;
- case posRight:
- tcBox.left = tcBox.right - tcGutter - tcWidth - tcGutter;
- break;
- }
-
- // Draw the background
- OpColor(&fiftyPercentGray);
- RGBForeColor(&bs->bkgdColor);
- PenMode(blend);
- PaintRect(&tcBox);
-
- // Draw the timecode
- PenNormal();
- GetFontInfo(&info);
- RGBForeColor(&bs->textColor);
- MoveTo(tcBox.left + tcGutter, tcBox.bottom - info.descent);
- DrawString(timeStr);
- }
-